#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>

using namespace std;

struct ThreadInfo { //封装线程ID和名字
    pthread_t tid;
    string name;
};

static const int defaultnum = 5;

template <class T>
class ThreadPool {
public:
    void Lock() { pthread_mutex_lock(&mutex_); }
    void Unlock() { pthread_mutex_unlock(&mutex_); }
    void Weakup() { pthread_cond_signal(&cond_); }
    void ThreadSleep() { pthread_cond_wait(&cond_, &mutex_); }
    bool IsQueueEmpty() { return tasks_.empty(); }
    string GetThreadName(pthread_t tid) {
        for (const auto& ti : threads_)
            if (ti.tid == tid)
                return ti.name;
        return "None";
    }
public:

    //如果将线程执行函数放在类内，那么类的成员函数还会有个隐藏的this指针参数。所以参数个数不对
    // void* HandlerTask(void* args) { 
    static void* HandlerTask(void* args) { //加static就没有this指针参数
    ThreadPool<T>* tp = static_cast<ThreadPool<T>*>(args);
    string name = tp->GetThreadName(pthread_self());
        while (true) {
            tp->Lock();
            while (tp->IsQueueEmpty()) {
                tp->ThreadSleep();
            }
            T t = tp->Pop();
            tp->Unlock();
            t();
            // cout << name << " run, result: " << t.GetResult() << endl;
        }
    }

    void Start() {
        int num = threads_.size();
        for (int i = 0; i < num; i++) {
            threads_[i].name = "thread-" + to_string(i+1);
            // pthread_create(&threads_[i].tid, nullptr, HandlerTask, nullptr);//编译不通过，因为HandlerTask函数是静态成员函数
            pthread_create(&threads_[i].tid, nullptr, HandlerTask, this);//传当前线程池对象（ThreadPool实例）的地址
        }
    }

    T Pop() {
        T t = tasks_.front();
        tasks_.pop();
        return t;
    }

    //如果先解锁再唤醒。可能没有现成在等导致信号“丢失”。那线程就可能永远沉睡，再也没人通知它有任务来
    void Push(const T& t) {
        Lock();
        tasks_.push(t);
        Weakup();
        Unlock();
    }
    // //只在第一次创建单例对象时有并发问题，需要保护。
    // //如果对申请单例加锁，那么往后的线程都要经历申请锁->判断->释放锁。（即后续线程都要串行申请单例）
    // static ThreadPool<T>* GetInstance() {
    //     pthread_mutex_lock(&lock_);
    //     if (nullptr == tp_) {
    //         cout << "log: singleton create done first!" << endl;
    //         tp_ = new ThreadPool<T>;
    //     }
    //     pthread_mutex_unlock(&lock_);
    //     return tp_;
    // }
    static ThreadPool<T>* GetInstance() {
        // 外层检查：如果单例已存在，无需加锁，直接返回，减少锁竞争
        if (nullptr == tp_) { //开关，可以并发获取单例(第一次检查：避免已创建后仍频繁加锁，提高性能)
            pthread_mutex_lock(&lock_);
            if (nullptr == tp_) { //判断是否是单例
                cout << "log: singleton create done first!" << endl;
                tp_ = new ThreadPool<T>;
            }
            pthread_mutex_unlock(&lock_);
        }
        return tp_;
    }
private:
    ThreadPool(int num = defaultnum)
        :threads_(num) {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    } 
    ~ThreadPool() {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }
    ThreadPool(const ThreadPool<T>&) = delete; 
    ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;  
private:
    vector<ThreadInfo> threads_;//将封装的线程结构体放入vector
    queue<T> tasks_; //任务队列
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;
    static ThreadPool<T>* tp_;
    static pthread_mutex_t lock_;//获取单例时需要加锁
};
template <class T>
ThreadPool<T>* ThreadPool<T>::tp_ = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

